home *** CD-ROM | disk | FTP | other *** search
-
- *-------------------------------------------------------*
- * AFD concept overview: *
- *-------------------------------------------------------*
-
- The AFD system simply allows Apex to read & write image
- file formats using external file support modules. These
- modules can be recognised by their file extension *.AFD.
- You will find some commonly used formats supplied in this
- form alongside Apex Alpha itself.
-
- One benefit of this system is to allow users/developers
- to produce their own AFD support modules where necessary,
- providing that development details are freely available.
- Fortunately, the AFD format is described here in great
- detail, in the hope that users will release a multitude
- of new drivers for the program. That's the idea anyway.
-
- *-------------------------------------------------------*
- * AFD implementation: *
- *-------------------------------------------------------*
-
- The AFD file format consists of a small (executable)
- program which Apex will automatically load from the
- default AFD path into memory and immediately execute as
- if it were a normal TOS program.
-
- *-------------------------------------------------------*
-
- 1) First call to module / initialisation.
-
- At this point, the AFD module should make any special
- initialisation calls required to set up internal global
- structures, global variables or even data buffers in
- extreme cases.
-
- The AFD program should at this point also fill out the
- relevant function pointers & format specific variables
- of the global afd_structure, which are used for future
- calls made to the AFD from Apex itself.
-
- The initialisation call to the AFD module takes place in
- the USER mode processor state (normal operating mode),
- and will only ever happen once. The initialisation part
- of the module can be written in the form of a simple
- function or subroutine, or as a fully implemented Pterm /
- Pterm0 terminated program. Both systems are handled for
- the benefit of C-compiled modules which can prove
- difficult when attempting to generate raw (but still
- relocatable) external function-based modules like these.
-
- *-------------------------------------------------------*
-
- 2) Function calls to module.
-
- All future calls to the AFD module will be made via the
- afd_structure, which should now contain pointers to the
- appropriate 'examine', 'decoder' & 'encoder' functions
- after the initialisation call described previously. These
- function calls will always be made in SUPERVISOR mode
- processing state (i.e. protected mode) and will ALWAYS
- be treated as normal functions or subroutines.
-
- *-------------------------------------------------------*
- * AFD rules & Apex compatibility issues: *
- *-------------------------------------------------------*
-
- There are a few rules and some limitations imposed on the
- AFD module's actions & capabilities, but the restrictions
- are far less severe than you might expect. We have gone
- to great lengths to make life as easy as possible for the
- prospective AFD developer.
-
- The most important rules are specified here, in outline
- form - partly to help the developer avoid pitfalls and
- partly to show how Apex interfaces with the module. It
- is wise to skim this section at the very least, if not
- absorb it in detail.
-
- *-------------------------------------------------------*
-
- 1) Programming considerations:
-
- The program code does NOT have to be position independent,
- although it CAN be if this is required by the programmer.
-
- Apex expects a fully relocatable GEMDOS executable, where
- the first piece of executable code encountered is the
- initialisation routine. In the case of 'C', this will be
- standard startup code, including a call to function 'main',
- and terminated with a 'Pterm' call. In the case of ASM
- however, this will just be a simple module initialisation
- subroutine, terminated with an 'rts' instruction.
-
- *-------------------------------------------------------*
-
- 2) Memory initialisation:
-
- The TOS 'Mshrink' call IS available for compatibility
- reasons, but it does absolutely nothing.
-
- Apex will automatically calculate how much space is used
- by the module's TEXT, DATA & BSS sections and reserve the
- correct amount, which makes Mshrink redundant in most
- situations - including 'C' startup code.
-
- The module will have exactly 4096 bytes of additional TPA
- space (i.e. un-shrunk memory) available on execution for
- the stack, which although useless for ASM developers, is
- necessary in the case of C startup code, which will most
- often attempt to place the stack pointer at the very end
- of the TPA. 4kB should be enough for any file encoding /
- decoding function to operate perfectly.
-
- *-------------------------------------------------------*
-
- 3) Memory allocation/deallocation:
-
- The TOS 'Malloc', 'MXalloc' & 'Mfree' calls are always
- available, but they have been routed through the internal
- Apex memory manager. Although radically different from
- the TOS allocation system, the internal functions emulate
- the standard calls perfectly, except in the case of
- Mshrink, which disabled, and is of no consequence here.
-
- There is effectively no limit placed on the number of
- Malloc calls which can be made inside the module, and
- defragmentation is not much of a problem either. Apex
- handles this much better than the standard TOS memory
- pool. It is however wise to be careful with allocation
- order and block size, as there's no point in trying to
- make life difficult for Apex for no good reason.
-
- Memory blocks can be left behind as permanent storage,
- and they will not be freed unless the special 'salloc'
- call has been used in place of malloc (which stacks the
- block handles and releases all un-freed blocks on module
- termination - for lazy people!) when the module returns
- control to Apex. This may be necessary in some cases, but
- is not good practice and should be avoided wherever
- possible.
-
- No harm will come to any blocks deliberately left behind
- by the module if the programmer needs to do this. 'C'
- programs will often leave structures behind permanently,
- depending on what is going on in the code.
-
- *-------------------------------------------------------*
-
- 4) File activity:
-
- The standard Fopen / Fclose / Fread / Fwrite etc. calls
- are of course available for ease of use and compatibility
- reasons, but it is better to use the internal Apex file
- support functions because Apex then has the ability to
- report errors properly via internal dialog boxes.
-
- Do not leave the AFD module without closing all of your
- files. Apex does not do this for you.
-
- *-------------------------------------------------------*
-
- 5) Module termination (memory):
-
- Do NOT rely on the standard TOS 'Pterm' or 'Pterm0'
- termination calls to release ANY remaining memory blocks
- after the module is finished doing it's job. This means
- during the initialisation call specifically, since the
- function calls should not be terminated in this way
- under any circumstances.
-
- Any calls made to the STANDARD malloc functions (esp. in
- the case of 'C' based module development) will REMAIN
- allocated until Apex ITSELF terminates, unless the module
- cleans up after itself - which is a good idea if you want
- to avoid 'runaway' memory leakage problems.
-
- *-------------------------------------------------------*
-
- 6) Termination rules:
-
- Don't terminate the module with a 'Ptermres' - that's
- just plain silly!
-
- All calls which complete without errors should return
- a value of zero (0L) either as a function return value
- (for 'C') or in register 'D0' (for ASM). Any calls which
- fail or encounter a fatal error should return -1 instead,
- so Apex can deal with the consequences. Failure to adhere
- to these return codes can lead to dangerous AFD files.
-
- *-------------------------------------------------------*
- * Apex -> AFD module calling details: *
- *-------------------------------------------------------*
-
- 1) The initialisation function (function 'main').
-
- The first thing the module should do (main function in
- 'C', or equivalent subroutine in ASM) is find the global
- Apex communication structure, which is officially called
- afd_structure in the examples. After finding the address
- of this structure, it should be filled out with module
- specific details including function pointers and serial
- numbers. There are several very useful function pointers
- already present in the structure for the benefit of the
- module itself, covering file read/write and memory
- allocation calls. These are optional, and it may be useful
- to read these function addresses into global function
- pointers for later use.
-
- What follows is a simple example covering a bare minimum
- implementation of the AFD initialisation sequence.
-
- An assembly programmer would something like this...
-
- ; Get AFD structure base address.
-
- main: move.w #2001,-(sp)
- trap #14
- addq.l #2,sp
- move.l d0,afd_structure_ptr
- move.l d0,a0
-
- ; Place file extension string pointer in AFD structure.
-
- move.l #extension_string,afd_extension(a0)
-
- ; Fill out AFD structure with function pointers.
-
- move.l #inquire_routine,afd_inquire(a0)
- move.l #decoder_routine,afd_decode(a0)
- move.l #encoder_routine,afd_encode(a0)
-
- ; Choose a 16-bit colour for displaying format inside Apex.
-
- move.w #highlight_colour,afd_colour(a0)
-
- ; Choose a (hopefully) unique file format identifier.
-
- move.w #serial,afd_id(a0)
-
- ; Make copies of all available Apex function pointers,
- ; because it's much easer to call them 'indirect absolute'
- ; using 'jsr ([function_ptr.l])' than it is to call them
- ; straight from the structure!
-
- move.l afd_malloc(a0),malloc_ptr
- move.l afd_dealloc(a0),dealloc_ptr
- move.l afd_salloc(a0),salloc_ptr
- move.l afd_thread(a0),thread_ptr
- move.l afd_open(a0),open_ptr
- move.l afd_close(a0),close_ptr
- move.l afd_create(a0),create_ptr
- move.l afd_read(a0),read_ptr
- move.l afd_write(a0),write_ptr
- move.l afd_seek(a0),seek_ptr
- move.l afd_examine(a0),examine_ptr
- move.l afd_patch(a0),patch_ptr
-
- ; Return control to Apex
-
- rts
-
- Where a 'C' developer would use something like this...
-
- char *extension = "tga"; /* file extension string */
-
- long main()
- {
- struct alpha *alpha_ptr;
-
- /* Get AFD structure base address */
-
- alpha_ptr = Alphabase();
-
- /* Place file extension string pointer in AFD structure */
-
- alpha_ptr -> afd_extension = extension_string;
-
- /* Fill out AFD structure with function pointers */
-
- alpha_ptr -> afd_inquire = &inquire_function;
- alpha_ptr -> afd_decode = &decode_function;
- alpha_ptr -> afd_encode = &encode_function;
-
- /* Choose a 16-bit colour for displaying format inside Apex */
-
- alpha_ptr -> afd_colour = 0x1234;
-
- /* Choose a (hopefully) unique file format identifier */
-
- alpha_ptr -> afd_id = serial;
-
- return 0L;
- };
-
- Note: Header files are supplied for 'C' and ASM programmers
- to make these calls & access the AFD structures shown in
- these examples.
-
- *-------------------------------------------------------*
-
- 2) The image 'inquire' function:
-
- This function simply examines the header of the file
- indicated in the filename buffer 'adf_filename' and if the
- file is valid, returns the width & height in the adf_width
- & adf_height structure fields. If the file is invalid,
- then the adf_width & adf_height fields should be zero, and
- a -1L return code passed instead of 0L.
-
- Here is an example of a basic image-inquire function.
-
-
- Assembly language example:
-
-
- inquire_function:
-
- ; Open the file for read-only access
-
- move.w #none,file_handle
- move.l struct_ptr,a6
- lea afd_filename(a6),a0
- moveq #0,d0
- jsr ([open_ptr.l])
- tst.l d0
- bmi.s .error
- move.w d0,file_handle
-
- ; Read the file header
-
- moveq #our_header_size,d1
- move.l struct_ptr,a6
- lea afd_gpbuffer(a6),a0
- jsr ([read_ptr.l])
- tst.l d0
- bmi.s .error
-
- ; Update the adf_structure to reflect the image size
-
- move.l struct_ptr,a6
- lea afd_gpbuffer(a6),a0
- move.w our_image_width(a0),d1
- move.w our_image_height(a0),d2
- cmp.w #5120,d1 ; rudimentary validation
- bhi.s .error
- cmp.w #5120,d2 ; rudimentary validation
- bhi.s .error
- move.l struct_ptr,a6
- move.w d1,afd_width(a6)
- move.w d2,afd_height(a6)
-
- ; Return control to Apex - '0' return code for success.
-
- .done: moveq #0,d0
- bra.s .exit
-
- ; Return control to Apex - '-1' return code for error.
-
- .error: move.l struct_ptr,a6
- clr.w afd_width(a6)
- clr.w afd_height(a6)
- moveq #-1,d0
-
- ; Close file and return. '-1' file handles are ignored.
-
- .exit: move.l d0,-(sp)
- move.w file_handle,d0
- jsr ([close_ptr.l])
- move.l (sp)+,d0
- rts
-
-
- A simple 'C' implementation:
-
- long inquire_function()
- {
-
- long exitcode;
- struct alpha *alpha_ptr;
-
- /* this is just an imaginary structure for the file reader */
-
- struct imagestuff *image_info;
-
- /* Get AFD structure base address */
-
- alpha_ptr = Alphabase();
-
- /* Examine the file, reading header into a suitable structure */
- /* 'adf_filename' is the 1k filename BUFFER - it's NOT a pointer! */
-
- exitcode = examine_image(&(alpha_ptr -> afd_filename),image_info)
-
- /* Only update afd_structure if the file was valid */
-
- if !(exitcode)
- {
- alpha_ptr -> afd_width = image_info -> image_width;
- alpha_ptr -> afd_height = image_info -> image_height;
- }
-
- /* Return control to Apex */
-
- return exitcode;
-
- }
-
- *-------------------------------------------------------*
-
- 3) The image 'decoder' function:
-
- This function should take the same shape as the inquire
- function, but should concentrate on decoding the image
- data into the space located by the pointer 'adf_imageptr'.
-
- Again, the filename is passed in the 1k buffer called
- 'adf_filename'. A general purpose 1k buffer is also
- provided for convenience.
-
- DO NOT change the afd_width & afd_height fields in the
- afd_structure, as these are required by Apex for other
- purposes not covered here. The correct amount of space
- will be allocated before the decoder function is called,
- based on the width & height previously returned by the
- inquire function.
-
- The format into which the image should be decoded is
- as follows:
-
- Each pixel consists of 4 bytes. RED, GREEN, BLUE and
- ALPHA. All colour channels are zero before the decoder is
- called, so it's not necessary to fill out the ALPHA
- channel if it is not available.
-
- Pixel format: $RR,$GG,$BB,$AA
-
- The image buffer will simply be (width * height * 4) bytes
- in size. No dithering or colour reduction is required.
-
- *-------------------------------------------------------*
-
- 4) The image 'encoder' function:
-
- Same as decoder, but works in the other direction.
-
- <unfinished>
-
- *-------------------------------------------------------*
- * Detailed description of 'afd_structure' *
- *-------------------------------------------------------*
-
- afd_malloc /* Apex Malloc routine (in) */
-
- This points to the internal Apex malloc function. The
- parameters & return codes are the same as TOS malloc,
- except for the fact that -1L can be returned on an error
- instead of the usual 0L.
-
- d0.l = block size, or -1 for largest block.
- d1.l = memory type (0->3 as with TOS Mxalloc)
-
- Returns -1L on error, or size of largest block.
-
- *-------------------------------------------------------*
-
- afd_dealloc /* Apex Mfree routine (in) */
-
- This is the matching Apex mfree function. It will
- deallocate blocks allocated with either adf_malloc or
- adf_salloc. Parameters & codes match that of TOS.
-
- d0.l = block address (handle) to deallocate.
-
- Returns -1L on error.
-
- *-------------------------------------------------------*
-
- afd_salloc /* Apex stacked malloc routine */
-
- This is identical to the afd_malloc routine, except
- it records all block handles successfully allocated so
- they may be automatically freed by Apex when the module
- returns control. It is a dirty practice, but it can
- make life easier for some. It can also cut down the
- size and complexity of otherwise simple ASM modules
- due to reduced error handling requirements. Avoid using
- this for large operations, as it is not an efficent
- way to handle your resources.
-
- *-------------------------------------------------------*
-
- afd_thread /* Apex background thread (in) */
-
- Callback function. Call this every so often to update
- the very low-priority background jobs taking place inside
- the main Apex core. Things like memory indicators can
- be refreshed with this call.
-
- *-------------------------------------------------------*
-
- afd_open /* Fopen (in) */
-
- Same as TOS Fopen file function.
-
- a0.l = filename
- d0.w = mode
-
- Return parameters & codes match those of TOS.
-
- *-------------------------------------------------------*
-
- afd_close /* Fclose (in) */
-
- Same as TOS Fclose function. Returns -1 on error
- and ignores -1 handles, to make life a little easier
- for programmers who use the -1 code for 'unopened'
- file status on global file handles.
-
- d0.w = handle
-
- Returns -1L on error, otherwise matches TOS return
- codes.
-
- *-------------------------------------------------------*
-
- afd_create /* Fcreate (in) */
-
- a0.l = filename
-
- Same as TOS Fcreate function.
-
- Return codes match those of TOS.
-
- *-------------------------------------------------------*
-
- afd_read /* Fread (in) */
-
- Same as TOS Fread, except it will return an error for
- 'truncated' reads. TOS compatible return codes are
- always returned in d1 if they are required.
-
- d0.w = handle
- d1.l = size
- a0.l = buffer
-
- Returns -1L in d0 on a truncated read.
- Returns TOS error codes in d1 - and also in d0 when read
- is not truncated.
-
- *-------------------------------------------------------*
-
- afd_write /* Fwrite (in) */
-
- Same as afd_read, but for writing. Same codes and
- parameters are used as with afd_read.
-
- *-------------------------------------------------------*
-
- afd_seek /* Fseek (in) */
-
- Same as TOS Fseek.
-
- d0.w = handle
- d1.w = mode
- d2.l = size
-
- Return codes match those of TOS.
-
- *-------------------------------------------------------*
-
- afd_examine /* Fseek + Fread (in) */
-
- Combined seek & read operation. Ideal for examining
- simple file headers etc.
-
- d0.w = handle
- d1.l = size
- d2.l = index
- a0.l = buffer
-
- Returns -1L on seek error, but otherwise matches TOS
- Fread return codes.
-
- *-------------------------------------------------------*
-
- afd_patch /* Fseek + Fwrite (in) */
-
- Combined seek & write operation. Ideal for updating
- simple file headers etc.
-
- Parameters & codes match those of 'afd_examine', with
- Fwrite return codes.
-
- *-------------------------------------------------------*
-
- afd_extension /* pointer to format extension string (out) */
-
- This is a longword pointer to a short zero-terminated string
- containing the ascii file extension of the format supported
- by the AFD module. This field MUST be updated by the module
- during it's initialisation call. The string buffer should
- be supplied by the module itself.
-
- *-------------------------------------------------------*
-
- afd_inquire /* format inquire routine address (out) */
-
- This is the function pointer for the routine which Apex
- calls to examine any files encountered with the file
- extension indicated by 'afd_extension' (above). This
- field MUST be updated during the module initialisation
- stage. This function should update the afd_width &
- afd_height fields of the afd_structure if the file is
- valid, and return a 0L code for success, or -1L for a
- fatal error.
-
- *-------------------------------------------------------*
-
- afd_decode /* format decoder routine address (out) */
-
- This function decodes the image into a buffer (created
- by Apex using the afd_width & afd_height fields updated
- earlier with afd_inquire). The buffer can be found using
- the afd_imageptr field, which should only ever be read,
- and never be modified directly by the driver. The routine
- should return 0L for success, or -1L for a fatal error.
-
- *-------------------------------------------------------*
-
- afd_encode /* format encoder routine address (out) */
-
- Identical to afd_decode, but for saving files instead
- of loading them.
-
- *-------------------------------------------------------*
-
- afd_colour /* format highlight colour (out) */
-
- A colour encoded in %RRRRRGGGGGGBBBBB format which is
- used to represent the file format inside Apex itself.
-
- *-------------------------------------------------------*
-
- afd_id /* format id (out) */
-
- A unique serial number used to differentiate between file
- formats with the same file extension, but different
- encode/decode AFD modules. Although it is not yet supported,
- it is wise to fill the value with something meaningful
- to avoid future conflicts.
-
- *-------------------------------------------------------*
-
- afd_width /* image width (in/out) */
- afd_height /* image height (in/out) */
-
- These should only ever be modified by the afd_inquire
- routine, but can be read by the afd_decode & afd_encode
- functions to work out image dimensions.
-
- *-------------------------------------------------------*
-
- afd_imageptr /* 32bit imagebuffer pointer (in) */
-
- This should never be modified, and points to the x * y * 4
- byte buffer into which the image should be decoded, or
- from which the image should be saved.
-
- *-------------------------------------------------------*
-
- afd_filesize /* file size in bytes (in) */
-
- This holds the size of the file in question. Do not
- modify.
-
- *-------------------------------------------------------*
-
- afd_filename /* 1k filename string buffer (in) */
-
- This is a 1024 byte buffer (not a pointer) which contains
- the full path and filename of the file to be examined,
- loaded or written to disk. It is always zero terminated.
- Do not modify.
-
- *-------------------------------------------------------*
-
- afd_gpbuffer /* 1k general purpose buffer (in) */
-
- This is a 1024 byte general purpose buffer which can be
- useful for temporary work, and for reading file headers
- for examination. It will be trashed when the module
- returns control to Apex, so don't leave any important
- data behind that you might want back!
-
- *-------------------------------------------------------*
-